package mspbots.next.ticket.core.grader.interceptor;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import mspbots.next.ticket.core.grader.AbstractGradeRuleAdapter;
import mspbots.next.ticket.core.grader.GradeRuleInterceptorRegistration;
import mspbots.next.ticket.core.points.PointResult;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

@Log4j2
@Service(value = "SELECTED_ASSIGNED_POINT_RULE")
public class SelectedAssignedRuleInterceptor extends AbstractGradeRuleAdapter {

    private static final String RULE_KEY = "SelectedAssigned";
    private List<BoardAssignedParam> params;
    private String identifier;

    @Override
    public Mono<GradeRuleInterceptorRegistration> prepare(GradeRuleInterceptorRegistration gradeRuleInterceptorRegistration) {
        return Flux.just()
                .doFinally(r -> {
                    this.params = super.objectMapper
                            .convertValue(gradeRuleInterceptorRegistration.getRule().getParams(), new TypeReference<>() {
                            });
                    this.identifier = gradeRuleInterceptorRegistration.getRule().getRequest().getIdentifier();
                })
                .then(Mono.just(gradeRuleInterceptorRegistration));
    }

    @Override
    public Mono<PointResult> scoring(JsonNode ticket) {
        AtomicInteger order = new AtomicInteger();
        Integer statusId = super.getIntValueId(ticket.get("status"));

        if (StringUtils.hasLength(this.identifier)) {
            params.stream().filter(p -> p.isSelected()
                    && !CollectionUtils.isEmpty(p.getIdentifiers())
                    && !CollectionUtils.isEmpty(p.getStatusIds())
                    && p.getStatusIds().contains(statusId)
                    && p.getIdentifiers().contains(this.identifier))
                    .findFirst().ifPresent(item -> order.set(item.getPoints()));
        }
        return Mono.just(PointResult.withDefault().point(order.get())
                .detail(PointResult.Detail.with(order.get(),
                        Map.of("statusName", super.getStringValueName(ticket.get("status")), "identifier", this.identifier), RULE_KEY)));

    }

    @Data
    private static class BoardAssignedParam {
        private List<String> identifiers;
        private List<Integer> statusIds;
        private Integer points;
        private boolean selected;
    }

}
